from datetime import date, datetime
from typing import List, Optional
from uuid import UUID

from pydantic import BaseModel, EmailStr, ConfigDict, Field, field_validator

from app.models.user import (
    DocumentType,
    Gender,
    UserType,
    VerificationStatus,
)
from app.schemas.base import BaseSchema

PHONE_MIN_LENGTH = 6
PASSWORD_MIN_LENGTH = 8


class UserBase(BaseModel):
    phone: str
    email: Optional[EmailStr] = None
    username: Optional[str] = None
    nickname: Optional[str] = None
    avatar: Optional[str] = None
    full_name: Optional[str] = None
    document_type: Optional[DocumentType] = None
    document_number: Optional[str] = None
    gender: Optional[Gender] = None
    birth_date: Optional[date] = None
    is_active: bool = True
    is_superuser: bool = False
    user_type: UserType = UserType.PATIENT
    verification_status: VerificationStatus = VerificationStatus.APPROVED

    @field_validator("phone")
    @classmethod
    def validate_phone(cls, value: str) -> str:
        if not value or len(value) < PHONE_MIN_LENGTH:
            raise ValueError("手机号格式不正确")
        return value


class UserCreate(UserBase):
    password: str
    agreed_at: Optional[datetime] = None

    @field_validator("password")
    @classmethod
    def validate_password(cls, value: str) -> str:
        if len(value) < PASSWORD_MIN_LENGTH:
            raise ValueError(f"密码长度不能少于 {PASSWORD_MIN_LENGTH} 位")
        if value.isdigit() or value.isalpha():
            raise ValueError("密码需包含字母和数字")
        return value


class UserUpdate(BaseModel):
    phone: Optional[str] = None
    email: Optional[EmailStr] = None
    username: Optional[str] = None
    nickname: Optional[str] = None
    avatar: Optional[str] = None
    full_name: Optional[str] = None
    document_type: Optional[DocumentType] = None
    document_number: Optional[str] = None
    gender: Optional[Gender] = None
    birth_date: Optional[date] = None
    password: Optional[str] = None
    is_active: Optional[bool] = None
    is_superuser: Optional[bool] = None
    verification_status: Optional[VerificationStatus] = None
    agreed_at: Optional[datetime] = None
    last_login_at: Optional[datetime] = None

    @field_validator("password")
    @classmethod
    def validate_new_password(cls, value: Optional[str]) -> Optional[str]:
        if value is not None:
            if len(value) < PASSWORD_MIN_LENGTH:
                raise ValueError(f"密码长度不能少于 {PASSWORD_MIN_LENGTH} 位")
            if value.isdigit() or value.isalpha():
                raise ValueError("密码需包含字母和数字")
        return value


class UserInDB(UserBase):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    hashed_password: str
    agreed_at: Optional[datetime] = None
    last_login_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime


class User(BaseSchema):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    phone: str
    email: Optional[EmailStr] = None
    username: Optional[str] = None
    nickname: Optional[str] = None
    avatar: Optional[str] = None
    full_name: Optional[str] = None
    document_type: Optional[DocumentType] = None
    document_number: Optional[str] = None
    gender: Optional[Gender] = None
    birth_date: Optional[date] = None
    is_active: bool
    is_superuser: bool
    user_type: UserType
    verification_status: VerificationStatus
    agreed_at: Optional[datetime] = None
    last_login_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime


class UserLogin(BaseModel):
    identifier: str
    password: str
    user_type: UserType
    remember_me: bool = False
    agree_protocol: bool = True

    @field_validator("identifier")
    @classmethod
    def validate_identifier(cls, value: str) -> str:
        if not value:
            raise ValueError("请输入手机号或证件号")
        return value

    @field_validator("agree_protocol")
    @classmethod
    def validate_agreement(cls, value: bool) -> bool:
        if not value:
            raise ValueError("请先同意服务协议和隐私协议")
        return value


class PatientProfileBase(BaseModel):
    height_cm: Optional[float] = None
    weight_kg: Optional[float] = None
    bmi: Optional[float] = None
    emergency_contact: Optional[str] = None
    emergency_phone: Optional[str] = None


class PatientProfileCreate(PatientProfileBase):
    user_id: UUID


class PatientProfileUpdate(BaseModel):
    height_cm: Optional[float] = Field(default=None, ge=0, description="身高，单位厘米")
    weight_kg: Optional[float] = Field(default=None, ge=0, description="体重，单位千克")

    @field_validator("height_cm", "weight_kg")
    @classmethod
    def validate_positive(cls, value: Optional[float]) -> Optional[float]:
        if value is not None and value == 0:
            raise ValueError("身高或体重不能为0")
        return value


class PatientProfile(BaseSchema):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    user_id: UUID
    height_cm: Optional[float] = None
    weight_kg: Optional[float] = None
    bmi: Optional[float] = None
    emergency_contact: Optional[str] = None
    emergency_phone: Optional[str] = None
    created_at: datetime
    updated_at: datetime


class DoctorProfileBase(BaseModel):
    qualification_certificate_no: Optional[str] = None
    registration_certificate_no: Optional[str] = None
    hospital_code: Optional[str] = None
    department_code: Optional[str] = None
    title_code: Optional[str] = None


class DoctorProfileCreate(DoctorProfileBase):
    user_id: UUID


class DoctorCertificateFile(BaseSchema):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    profile_id: UUID
    file_id: UUID
    created_at: datetime
    updated_at: datetime


class DoctorProfile(BaseSchema):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    user_id: UUID
    qualification_certificate_no: Optional[str] = None
    registration_certificate_no: Optional[str] = None
    hospital_code: Optional[str] = None
    department_code: Optional[str] = None
    title_code: Optional[str] = None
    audit_comment: Optional[str] = None
    certificates: List[DoctorCertificateFile] = Field(default_factory=list)
    created_at: datetime
    updated_at: datetime


class RegisterAccount(BaseModel):
    phone: str
    sms_code: str
    password: str
    confirm_password: str
    agree_protocol: bool

    @field_validator("phone")
    @classmethod
    def validate_account_phone(cls, value: str) -> str:
        if not value or len(value) < PHONE_MIN_LENGTH:
            raise ValueError("手机号格式不正确")
        return value

    @field_validator("password")
    @classmethod
    def validate_account_password(cls, value: str) -> str:
        if len(value) < PASSWORD_MIN_LENGTH:
            raise ValueError(f"密码需不少于 {PASSWORD_MIN_LENGTH} 位且包含字母和数字")
        if value.isdigit() or value.isalpha():
            raise ValueError("密码需包含字母和数字")
        return value

    @field_validator("confirm_password")
    @classmethod
    def validate_confirm_password(cls, value: str, info) -> str:
        password = info.data.get("password")
        if password and value != password:
            raise ValueError("两次输入的密码不一致")
        return value

    @field_validator("agree_protocol")
    @classmethod
    def validate_account_agreement(cls, value: bool) -> bool:
        if not value:
            raise ValueError("请勾选同意服务协议和隐私协议")
        return value


class PatientRegisterRequest(RegisterAccount):
    full_name: str
    document_type: DocumentType
    document_number: str
    gender: Gender
    birth_date: date
    profile: Optional[PatientProfileBase] = None


class DoctorRegisterRequest(RegisterAccount):
    full_name: str
    document_type: DocumentType
    document_number: str
    gender: Gender
    birth_date: date
    qualification_certificate_no: str
    registration_certificate_no: str
    hospital_code: str
    department_code: str
    title_code: str
    certificate_file_ids: List[UUID]

    @field_validator("hospital_code", "department_code", "title_code")
    @classmethod
    def validate_dict_code(cls, value: str) -> str:
        if not value or not value.strip():
            raise ValueError("请选择有效的字典选项")
        return value.strip()


class SmsCodeRequest(BaseModel):
    phone: str
    purpose: str

    @field_validator("phone")
    @classmethod
    def validate_sms_phone(cls, value: str) -> str:
        if not value or len(value) < PHONE_MIN_LENGTH:
            raise ValueError("手机号格式不正确")
        return value

    @field_validator("purpose")
    @classmethod
    def validate_sms_purpose(cls, value: str) -> str:
        if value not in ("register", "reset_password"):
            raise ValueError("验证码用途不合法")
        return value


class PasswordChange(BaseModel):
    old_password: str
    new_password: str

    @field_validator("new_password")
    @classmethod
    def validate_updated_password(cls, value: str) -> str:
        if len(value) < PASSWORD_MIN_LENGTH:
            raise ValueError(f"新密码长度不能少于 {PASSWORD_MIN_LENGTH} 位")
        if value.isdigit() or value.isalpha():
            raise ValueError("新密码需包含字母和数字")
        return value


class UserProfileResponse(BaseModel):
    """当前登录用户的档案信息，根据不同角色携带不同的扩展字段。"""

    user: User
    patient_profile: Optional[PatientProfile] = None
    doctor_profile: Optional[DoctorProfile] = None
